﻿using System;
using System.Collections.Generic;
using System.Text;

namespace Shapefile
{
    public enum ShapeType
    {
        /*      
                All the non-Null shapes in a shapefile are required to be of the same shape type. The
                values for shape type are as follows:
                Value   Shape Type
                0       Null Shape
                1       Point
                3       PolyLine
                5       Polygon
                8       MultiPoint
                11      PointZ
                13      PolyLineZ
                15      PolygonZ
                18      MultiPointZ
                21      PointM
                23      PolyLineM
                25      PolygonM
                28      MultiPointM
                31      MultiPatch
        */
        Null = 0,
        Point = 1,
        PolyLine = 3,
        Polygon = 5,
        MutiPoint = 8,
        PointZ = 11,
        PolyLineZ = 13,
        PolygonZ = 15,
        MultiPointZ = 18,
        PointM = 21,
        PolyLineM = 23,
        PolygonM = 25,
        MultiPointM = 28,
        MultiPatch = 31

    }
    public class ESRIHeader
    {
        public const int HeaderLength = 100;

        private const int ExpectedFileCode = 9994;
        private const int ExpectedVersion = 1000;

        private int fileCode_;
        private int fileLength_;
        private int version_;
        private ShapeType shapeType_;
        private double xMin_;
        private double yMin_;
        private double xMax_;
        private double yMax_;
        private double zMin_;
        private double zMax_;
        private double mMin_;
        private double mMax_;

        public ESRIHeader(byte[] headerBytes)
        {
            if (headerBytes == null)
            {
                throw new ArgumentNullException("headerBytes is null!");
            }

            if (headerBytes.Length != HeaderLength)
            {
                throw new InvalidOperationException(string.Format("headerBytes must be {0} bytes long", HeaderLength));
            }

            /*
                    Position    Field           Value           Type        Byte Order
                    Byte 0      File Code       9994            Integer     Big
                    Byte 4      Unused          0               Integer     Big
                    Byte 8      Unused          0               Integer     Big
                    Byte 12     Unused          0               Integer     Big
                    Byte 16     Unused          0               Integer     Big
                    Byte 20     Unused          0               Integer     Big
                    Byte 24     File Length     File Length     Integer     Big
                    Byte 28     Version         1000            Integer     Little
                    Byte 32     Shape Type      Shape Type      Integer     Little
                    Byte 36     Bounding Box    Xmin            Double      Little
                    Byte 44     Bounding Box    Ymin            Double      Little
                    Byte 52     Bounding Box    Xmax            Double      Little
                    Byte 60     Bounding Box    Ymax            Double      Little
                    Byte 68*    Bounding Box    Zmin            Double      Little
                    Byte 76*    Bounding Box    Zmax            Double      Little
                    Byte 84*    Bounding Box    Mmin            Double      Little
                    Byte 92*    Bounding Box    Mmax            Double      Little
            */

            fileCode_ = BinaryConverter.ToInt32(headerBytes, 0, ByteOrder.Big);

            if (fileCode_ != ExpectedFileCode)
            {
                throw new InvalidOperationException(string.Format("Header File code is {0}, expected {1}",
                    fileCode_,
                    ExpectedFileCode));
            }

            version_ = BinaryConverter.ToInt32(headerBytes, 28, ByteOrder.Little);
            if (version_ != ExpectedVersion)
            {
                throw new InvalidOperationException(string.Format("Header version is {0}, expected {1}",
                    version_,
                    ExpectedVersion));
            }

            fileLength_ = BinaryConverter.ToInt32(headerBytes, 24, ByteOrder.Big);
            shapeType_ = (ShapeType)BinaryConverter.ToInt32(headerBytes, 32, ByteOrder.Little);
            xMin_ = BinaryConverter.ToDouble(headerBytes, 36, ByteOrder.Little);
            yMin_ = BinaryConverter.ToDouble(headerBytes, 44, ByteOrder.Little);
            xMax_ = BinaryConverter.ToDouble(headerBytes, 52, ByteOrder.Little);
            yMax_ = BinaryConverter.ToDouble(headerBytes, 60, ByteOrder.Little);
            zMin_ = BinaryConverter.ToDouble(headerBytes, 68, ByteOrder.Little);
            zMax_ = BinaryConverter.ToDouble(headerBytes, 76, ByteOrder.Little);
            mMin_ = BinaryConverter.ToDouble(headerBytes, 84, ByteOrder.Little);
            mMax_ = BinaryConverter.ToDouble(headerBytes, 92, ByteOrder.Little);
        }

        public int FileCode
        {
            get { return fileCode_; }
        }

        public int FileLength
        {
            get { return fileLength_; }
        }

        public int Version
        {
            get { return version_; }
        }

        public ShapeType ShapeType
        {
            get { return shapeType_; }
        }

        public double XMin
        {
            get { return xMin_; }
        }
        public double YMin
        {
            get { return yMin_; }
        }

        public double XMax
        {
            get { return xMax_; }
        }

        public double YMax
        {
            get { return yMax_; }
        }

        public double Zmin
        {
            get { return zMin_; }
        }

        public double ZMax
        {
            get { return zMax_; }
        }

        public double MMin
        {
            get { return mMin_; }
        }

        public double MMax
        {
            get { return mMax_; }
        }
    }
}
